package com.web.common.tool;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 敏感词操作处理
 * 
 * @author zhouhui
 * @since 1.0.0
 */
public class SensitiveWordsUtil {

	private SensitiveWordsUtil() {}

	/**
	 * <pre>
	 * 将敏感词转成树形结构，最终获取类似下面的结构。
	 * {"测":{"试":null,"量":{"方":{"法":null}}}}
	 * </pre>
	 * @param words 敏感词信息
	 * @return Map<String, Object> 树形结构
	 *
	 * @author zhouhui
	 * @since 1.0.0
	 */
	@SuppressWarnings("unchecked")
	public static Map<String, Object> buildWordsTree(Set<String> words){
		Map<String, Object> dataMap = new HashMap<>();
		words.forEach(key -> {
			List<String> characterList = splitStr(key);
			if(characterList.isEmpty()) {
				return;
			}
			Map<String, Object> curMap = dataMap;
			for (int i = 0; i < characterList.size(); i++) {
				String character = characterList.get(i);
				Map<String, Object> tempMap = (Map<String, Object>) curMap.get(character);
				if(tempMap == null) {
					Map<String, Object> childMap = new HashMap<>();
					curMap.put(characterList.get(i), childMap);
					curMap = childMap;
				}else {
					curMap = tempMap;
				}
			}
		});
		return dataMap;
	}

	/**
	 * <pre>
	 * 通过DFA算法进行敏感词的筛选。
	 * 如果敏感词为“星”和“星期一”，对应语句“星234期一”则匹配不到！！
	 * </pre>
	 * @param sensitiveWords 敏感词的树结构
	 * @param str 查询的字符串
	 * @param step 词语之间的有效步长
	 * @return List<String> 查询到的敏感词
	 *
	 * @author zhouhui
	 * @since 1.0.0
	 */
	@SuppressWarnings("unchecked")
	public static List<String> getSensitiveWordsByDFA(Map<String, Object> sensitiveWords, String str, int step) {
		List<String> wordList = new ArrayList<>(str.length());
		int startPoint = 0;
		int movePoint = 0;
		int curStep = 0;
		int counter = 0;
		StringBuilder builder = new StringBuilder();
		Map<String, Object> tempMap = null;
		while(movePoint < str.length()) {
			if(counter == 0) {
				tempMap = sensitiveWords;
				movePoint = startPoint;
			}
			String charactor = str.substring(movePoint, movePoint + 1);
			Object value = tempMap.get(charactor);
			if((counter == 0 || curStep >= step)  && value == null) {
				startPoint += 1;
				movePoint = startPoint;
				counter = 0;
				curStep = 0;
				builder.setLength(0);
				continue;
			}
			
			if(counter > 0 && curStep < step && value == null) {
				builder.append(charactor);
				curStep += 1;
			}
			if(value != null) {
				tempMap = (Map<String, Object>) value;
				builder.append(charactor);
				curStep = 0;
			}
			counter += 1;
			movePoint += 1;
			
			if(tempMap.isEmpty()) {
				wordList.add(builder.toString());
				builder.setLength(0);
				startPoint = movePoint;
				counter = 0;
				curStep = 0;
			}
		}
		return wordList;
	}

	/**
	 * 将字符串按照字符进行拆分
	 * @param str 需要拆分的字符串
	 * @return List<String> 拆分后的字符列表
	 *
	 * @author zhouhui
	 * @since 1.0.0
	 */
	public static List<String> splitStr(String str) {
		if (str == null || "".equals(str)) {
			return new ArrayList<>();
		}
		List<String> strList = new ArrayList<>(str.length());
		char[] strChars = str.toCharArray();
		for (int i = 0; i < strChars.length; i++) {
			strList.add(strChars[i] + "");
		}
		return strList;
	}
}
